fix(web,jobs): reach Result ready instead of sticking on Retrieving result - #141
Merged
Merged
Conversation
Supplier delivery finishes in the worker, after the browser has already read the request list, so a request whose delivery was still PENDING at read time kept saying "Retrieving result" until someone pressed refresh — long after the result was durably available. Whether it looked right depended only on whether the worker beat the page load, which is why it worked intermittently. The list now re-reads itself while any delivery is PENDING: every four seconds, fifteen attempts, then it stops and leaves the manual refresh as the way to look again. The reads are GET /v1/jobs only. They never call the resume endpoint and never submit a payment, so at-most-once settlement is unaffected, and they do not raise the loading flag, because the spinner, the disabled button, and the tab fade belong to a read the operator asked for. This partially reverses a2903a1, which removed automatic polling after a report of unwanted traffic. The bound and the pending-only condition keep both reports satisfied; the resume control that commit removed stays removed. The browser spec asserted an exact list-read count, which a timed re-read makes timing-dependent; it now asserts a lower bound and still asserts that no resume request is sent.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
oneshot | 0f8dd9a | Sep 13 2026, 02:07 PM |
selezenart
marked this pull request as ready for review
September 13, 2026 14:10
This was referenced Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A request whose payment had settled kept showing "Retrieving result" long after the supplier result was available — intermittently, with no obvious trigger.
It was a stale snapshot, not a rendering fault.
JobListreadGET /v1/jobsonce on mount and then never again except through the manual "Refresh requests" button, while supplier delivery completes in the worker after that read. Whether the card looked right depended only on whether the worker beat the page load.The list now re-reads itself while any delivery is
PENDING: every four seconds, fifteen attempts (about a minute), then it stops and leaves the manual refresh as the way to look again.A second commit fixes the state-machine hole behind the same symptom. A committed job whose delivery reached
PENDINGcould be left with nothing able to move it: the worker no-ops a payload whosedelivery_attemptno longer matches and then marks the outbox rowDELIVERED, whileresumeDeliveryre-queued onlyNOT_REQUESTEDorRETRIEVAL_FAILED. Such a job kept a committed payment, an unretrieved result, and no path forward — and the bounded re-reads above would simply give up on it.PENDINGalone is still not resumable. The deciding evidence is whether afulfill_supplier_orderrow is still queued for that job; a row a worker currently holds isstatus = 'PENDING'and so counts as queued, so an in-flight retrieval is never duplicated. Only a job with no such row left is re-queued, under a freshdelivery_attemptthat fences the old retrieval, claimed by compare-and-set against the state read under the job'sFOR UPDATElock.Scope and acceptance criteria
PENDINGwith no queued fulfilment work can be recovered, while one that is genuinely queued or in flight is left alone.This partially reverses
a2903a1, which removed automatic polling after a report that follow-up reads created unwanted traffic. The bound and the pending-only condition are what satisfy both reports; the resume control that commit removed stays removed.Product and security invariants
Invariant notes:
The added reads are
GET /v1/jobsonly. They never call the resume endpoint and never submit a payment.The
resumeDeliverychange creates supplier-retrieval work only: nosubmit_settlementrow, no attempt row, no payment path, so1 intent / at most 1 committed settlementis untouched and the committed payment is preserved exactly as before. Claiming is a compare-and-set against the state read under the job'sFOR UPDATElock, so concurrent resumes cannot both claim one delivery, and the freshdelivery_attemptfences any older retrieval from completing. Selected.agent/TEST_MATRIX.mdcases: downstream failure after payment and duplicate/parallel claim.Validation
Commands and results:
The root vitest config includes only
.ts/.mjs, sopnpm testexercises none of the.tsxcomponents changed here;pnpm --filter @oneshot/web testis the run that covers them.Independent review evidence
Gate A — exact candidate tree before push
Reviewer tool:
free-pi-cliVerdict: skipped at the requester's explicit instruction
Findings or residual risks: Gate A was not run. This is a recorded deviation from
.agent/IMPLEMENTATION_LOOP.md§4-5, not a pass.The reviewed tree equals the committed tree.
Gate B — exact remote PR head
Pull request URL/number: this PR
Remote head commit SHA:
0f8dd9a1f4cdfa091206c053de491d0c5cc18239Reviewer tool:
free-pi-cliVerdict: skipped at the requester's explicit instruction
Findings or residual risks: Gate B was not run. Recorded deviation from §7, not a pass.
Gate B reviewed the current remote head and matches Gate A's approved tree, or a fresh Gate A was run for the changed tree.
Agent policy / repository-policyand all applicable CI checks pass.This PR is a draft and carries no independent review. Both gates should be run against the head before it leaves draft.
Risk and rollback
POST /v1/jobs/:jobId/resume, so recovering a stranded delivery still takes an API call. The control that used to do it was removed deliberately ina2903a1; re-adding one is a product decision rather than part of this fix.Human merge